<?php

declare(strict_types=1);

namespace zhtp\upload\disk;

use League\Flysystem\AwsS3V3\AwsS3V3Adapter;
use League\Flysystem\Visibility;
use think\helper\Arr;
use think\filesystem\Driver;
use Aws\S3\S3Client;
use League\Flysystem\AwsS3V3\PortableVisibilityConverter as AwsS3PortableVisibilityConverter;


use League\Flysystem\PathNormalizer;
use League\Flysystem\PathPrefixer;
use League\Flysystem\WhitespacePathNormalizer;


class S3 extends Driver
{
    protected function createAdapter(): AwsS3V3Adapter
    {
        $s3Config = $this->formatS3Config($this->config);
        $root = (string) ($s3Config['root'] ?? '');
        $visibility = new AwsS3PortableVisibilityConverter(
            $this->config['visibility'] ?? Visibility::PUBLIC
        );
        $streamReads = $s3Config['stream_reads'] ?? false;
        $client = new S3Client($s3Config);
        return new AwsS3V3Adapter($client, $s3Config['bucket'], $root, $visibility, null, $this->config['options'] ?? [], $streamReads);
    }

    protected function formatS3Config(array $config)
    {
        $config += ['version' => 'latest'];

        if (!empty($config['key']) && !empty($config['secret'])) {
            $config['credentials'] = Arr::only($config, ['key', 'secret', 'token']);
        }

        return Arr::except($config, ['token']);
    }


    /**
     * @var PathPrefixer
     */
    protected $prefixer;

    /**
     * @var PathNormalizer
     */
    protected $normalizer;

    protected function prefixer()
    {
        if (!$this->prefixer) {
            $this->prefixer = new PathPrefixer($this->config['root'], DIRECTORY_SEPARATOR);
        }
        return $this->prefixer;
    }

    protected function normalizer()
    {
        if (!$this->normalizer) {
            $this->normalizer = new WhitespacePathNormalizer();
        }
        return $this->normalizer;
    }

    /**
     * 获取文件访问地址
     * @param string $path 文件路径
     * @return string
     */
    public function url(string $path): string
    {
        $path = $this->normalizer()->normalizePath($path);

        if (isset($this->config['url'])) {
            return $this->concatPathToUrl($this->config['url'], $path);
        }
        return parent::url($path);
    }

    public function path(string $path): string
    {
        return $this->prefixer()->prefixPath($path);
    }
}